#include "fileTransfer.h"

/*
 * @brief 客户端请求下载文件
 *
 * @param sockfd 连接服务端的socket文件描述符
 * @param file_path 需要上传的文件路径（不支持上传目录）
 *
 * @return 成功返回 0
 */
int download(int sockfd, const char *file_name)
{
    tlv_t client_tlv;
    fileCheck_t file_check;
    int flag;

    // 发送文件名检查文件是否存在
    client_tlv.type = TYPE_METADATA;
    client_tlv.length = strlen(file_name);
    send(sockfd, &client_tlv, TLV_HEAD_SIZE, MSG_NOSIGNAL);
    send(sockfd, file_name, client_tlv.length, MSG_NOSIGNAL);

    // server 确认文件是否存在
    recv(sockfd, &client_tlv, TLV_HEAD_SIZE, MSG_WAITALL);
    recv(sockfd, &flag, client_tlv.length, MSG_WAITALL);

    // 请求的文件不存在
    if (flag == FILE_NOT_EXIST)
    {
        printf("蒜鸟蒜鸟，对方没这文件\n");
        return FILE_NOT_EXIST;
    }

    // 当前目录下存在同名文件，且存在它的.info文件
    if (isFileCheck(file_name) == FILE_EXIST) // 我管你这那，立即续传
    {
        // 发送续传标识
        flag = FILE_EXIST;
        client_tlv.type = TYPE_FLAG;
        client_tlv.length = sizeof(flag);
        send(sockfd, &client_tlv, TLV_HEAD_SIZE, MSG_NOSIGNAL); // 发送头
        send(sockfd, &flag, client_tlv.length, MSG_NOSIGNAL);

        // 读取并发送file_check给服务端
        fileCheckRead(file_name, &file_check);
        // send(sockfd, &file_check, sizeof(file_check), MSG_NOSIGNAL);
        client_tlv.type = TYPE_FILE_CHECK;
        client_tlv.length = sizeof(fileCheck_t);
        send(sockfd, &client_tlv, TLV_HEAD_SIZE, MSG_NOSIGNAL); // 发送头
        send(sockfd, &file_check, client_tlv.length, MSG_NOSIGNAL);

        // 创建文件并接收数据
        // int fd = open(file_name, O_WRONLY | O_APPEND | O_CREAT, 0644); // 追加
        int fd = open(file_name, O_WRONLY | O_CREAT, 0644);
        lseek(fd, file_check.file_offset, SEEK_SET); // 从文件开头偏移 offset

        clientRecvData(sockfd, fd, &file_check);

        close(fd);
    }
    else
    {
        // 发送新下载标识
        flag = FILE_NOT_EXIST;
        client_tlv.type = TYPE_FLAG;
        client_tlv.length = sizeof(flag);
        send(sockfd, &client_tlv, TLV_HEAD_SIZE, MSG_NOSIGNAL);
        send(sockfd, &flag, client_tlv.length, MSG_NOSIGNAL);

        // 接收并创建file_check
        recv(sockfd, &client_tlv, TLV_HEAD_SIZE, MSG_WAITALL);
        recv(sockfd, &file_check, client_tlv.length, MSG_WAITALL);

        // 下载新文件，创建同名的 filecheck.info 文件
        fileCheckCreate(file_name, &file_check);

        // 创建文件并接收数据(临时文件是否需要换后缀以避免用户读取未完成文件？)
        int fd = open(file_name, O_RDWR | O_CREAT | O_TRUNC, 0644); // 创建文件
        clientRecvData(sockfd, fd, &file_check);

        close(fd);
    }

    return 0;
}

/*
 * @brief 客户端接收客户端传输数据，并判断传输是否完成
 *
 * @param sockfd 连接客户端的socket文件描述符
 * @param fd 写入文件的文件描述符
 * @param file_check 保存下载信息的结构体
 *
 * @return 0-成功
 */
int clientRecvData(int sockfd, int fd, fileCheck_t *file_check)
{
    tlv_t recv_tlv;
    char *data = (char *)malloc(CHUNK_SIZE);
    // const char *file_name = file_check->file_name;

    // 文件下载完成度百分比
    off_t file_size = file_check->file_size;
    printf("filesize = %ld\n", file_size);

    off_t cur_size = file_check->file_offset; // 已接收的文件数据量
    off_t last_size = cur_size;               // 上次打印的cur_size
    off_t slice = file_size / 1000;           // 分片

    while (1)
    {
        recv(sockfd, &recv_tlv, TLV_HEAD_SIZE, MSG_WAITALL);
        if (recv_tlv.type == TYPE_ABORT)
        {
            break;
        }
        recv(sockfd, &data, recv_tlv.length, MSG_WAITALL);

        write(fd, data, recv_tlv.length); // 将接收到的数据写入fd文件描述符指向的文件

        // 打印下载进度条
        cur_size += recv_tlv.length;
        // 更新接收数据量
        file_check->file_offset = cur_size;
        if (cur_size - last_size > slice)
        {
            printf("download %lf%%\r", 100.0 * cur_size / file_size);
            fflush(stdout);
            last_size = cur_size;
        }
    }

    printf("download 100%%\n");
    free(data);
    return 0;
}
